package org.origin.centre.support.utils;

import org.springframework.beans.BeanUtils;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.Assert;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Spl表达式工具
 *
 * @author ferret
 * @version 2024-05-08
 */
@SuppressWarnings("unused")
public final class ExpressUtil {
    private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
    private static final StandardEvaluationContext CONTEXT = new StandardEvaluationContext();

    static {
        CONTEXT.addPropertyAccessor(new MapAccessor());
        // register("format", "format", ExpressUtil.class);
    }

    /**
     * 解析表达式
     */
    public static <T> T parse(String express, Object obj, Class<T> clazz, T defaultVal) {
        try {
            return EXPRESSION_PARSER.parseExpression(express).getValue(CONTEXT, obj, clazz);
        } catch (Exception e) {
            return defaultVal;
        }
    }

    /**
     * 是否是表达式
     */
    public static boolean is(String express) {
        try {
            EXPRESSION_PARSER.parseExpression(express);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 注册调用方法
     *
     * @param name      注册方法名称
     * @param signature 调用的cls的方法名称
     * @param cls       调用的cls
     */
    public static void register(String name, String signature, Class<?> cls) {
        Assert.isNull(CONTEXT.lookupVariable(name), "重复注册方法：" + name);
        CONTEXT.registerFunction(name, Objects.requireNonNull(BeanUtils.resolveSignature(signature, cls)));
    }

    /**
     * 注册类下的所有静态方法
     *
     * @param cls 目标类
     */
    @SuppressWarnings("unchecked")
    public static void register(Class<?> cls) {
        List<Method> list = ReflectUtils.addAllMethods(cls, new ArrayList<Method>());
        for (Method method : list) {
            if (method.getDeclaringClass().equals(cls) &&
                    Modifier.isStatic(method.getModifiers())) {
                register(method.getName(), method.toString(), cls);
            }
        }
    }
}
